package org.dairy.farms.dao.persistence;

import org.dairy.farms.dao.exception.PersistenceException;
import org.hibernate.Session;
import org.springframework.orm.hibernate3.HibernateCallback;

import java.io.Serializable;
import java.util.List;

/**
 * Created by IntelliJ IDEA.
 * User: gduggira
 * Date: Jun 9, 2011
 * Time: 5:48:13 PM
 */
public interface BasePersistence<T> {

    /**
     * Gets a Hibernate {@link org.hibernate.Session} object
     *
     * @return Hibernate {@link org.hibernate.Session} object
     */
    Session getSession();

    /**
     * Performs a HQL query against the database.
     *
     * @param query The HQL query
     *
     * @return Results from the query
     *
     * @throws PersistenceException Thrown on any errors during persistence
     */
    <T> List<T> find(String query) throws PersistenceException;

    /**
     * Performs a parameterized HQL query against the database.
     *
     * @param query  The HQL query
     * @param params Parameters to the query (like PreparedStatement params)
     *
     * @return Results from the query
     *
     * @throws PersistenceException Thrown on any errors during persistence
     */
    <T> List<T> find(String query, Object[] params) throws PersistenceException;

    /**
     * Performs a parameterized HQL query against the database.
     *
     * @param query The HQL query
     * @param param Parameters to the query (like PreparedStatement params)
     *
     * @return Results from the query
     *
     * @throws PersistenceException Thrown on any errors during persistence
     */
    <T> List<T> find(String query, Object param) throws PersistenceException;

    /**
     * Loads all persistence instances of the given entity class.
     *
     * @param clazz the persistent class
     *
     * @return a List containing 0 or more persistent instances
     *
     * @throws PersistenceException if there is a Hibernate error
     */
    <T> List<T> loadAll(Class<T> clazz) throws PersistenceException;

    /**
     * Loads an object given its unique id.
     *
     * @param clazz The class of the object to load
     * @param id    The unique id of the object
     *
     * @return The object with the given id and class
     *
     * @throws PersistenceException Thrown on any errors during persistence
     */
    <T> T load(Class<T> clazz, Serializable id) throws PersistenceException;

    /**
     * Loads an object from the database through a query.  Similar to the find
     * method, except that the result of the query must be a single object.
     *
     * @param query The HQL query
     * @param param Parameter to the query (like PreparedStatement param)
     *
     * @return Resulting object from the query
     *
     * @throws PersistenceException Thrown on any errors during persistence
     * @see #find(String, Object)
     */
    <T> T load(String query, Object param)
            throws PersistenceException;

    /**
     * Loads an object from the database through a query.  Similar to the find
     * method, except that the result of the query must be a single object.
     *
     * @param query  The HQL query
     * @param params Parameters to the query (like PreparedStatement params)
     *
     * @return Resulting object from the query
     *
     * @throws PersistenceException Thrown on any errors during persistence
     * @see #find(String, Object[])
     */
    <T> T load(String query, Object[] params)
            throws PersistenceException;

    /**
     * Saves an object to the database (INSERT statement).  The object must
     * be mapped by hibernate.
     *
     * @param obj The object to be saved
     *
     * @throws PersistenceException Thrown on any errors during persistence
     */
    void save(Object obj) throws PersistenceException;

    /**
     * Updates an object to the database (UPDATE statement).  The object must
     * be mapped by hibernate.
     *
     * @param obj The object to be updated
     *
     * @throws PersistenceException Thrown on any errors during persistence
     */
    void update(Object obj) throws PersistenceException;

    /**
     * Removes an object from the database (DELETE statement).  The object must
     * be mapped by hibernate.
     *
     * @param obj The object to be deleted
     *
     * @throws PersistenceException Thrown on any errors during persistence
     */
    void delete(Object obj) throws PersistenceException;

    /**
     * Refreshes an object from the database.  This object must be mapped by
     * hibernate.
     *
     * @param o The object that needs to be refreshed
     *
     * @throws PersistenceException Thrown when any errors happen
     */
    void refresh(Object o) throws PersistenceException;

    /**
     * Executes a HibernateCallback object similar to Spring's
     * HibernateTemplate except that exceptions are converted to
     * PersistenceExceptions.
     *
     * @param callback Callback to be executed
     *
     * @return The object returned by the callback
     *
     * @throws PersistenceException Thrown on any errors during persistence
     */
    <T> T execute(HibernateCallback callback) throws PersistenceException;

    /**
     * Performs a parameterized HQL query against the database using a named parameter.
     *
     * @param query     The HQL query
     * @param paramName the name of the parameter for substitution
     * @param value     value for the parameter
     *
     * @return Results from the query
     *
     * @throws PersistenceException Thrown on any errors during persistence
     */
    <T> List<T> findByNamedParam(String query, String paramName, Object value) throws PersistenceException;



    /**
     * Performs a parameterized HQL query against the database using named parameters and values.
     *
     * @param query     The HQL query
     * @param paramNames the name of the parameters for substitution
     * @param values     value for each of the parameter
     *
     * @return Results from the query
     *
     * @throws PersistenceException Thrown on any errors during persistence
     */
   <T> List<T> findByNamedParams(String query, String[] paramNames, Object[] values) throws PersistenceException;


    /**
     * We should not need to provide access to the HibernateTemplate and JDBCTemplate to external classes.
     * Although on second thoughts there can be places where it can be made use of. But still keeping it
     * commented out for now.
     //    /**
     //     * @return Returns the hibernateTemplate.
     //     */
//    HibernateTemplate getHibernateTemplate();
//
//    JdbcTemplate getJdbcTemplate();

    /**
     * @param query
     * @param <T>
     *
     * @return
     *
     * @throws PersistenceException
     */
    <T> List<T> findByNamedQuery(String query) throws PersistenceException;

    <T> List<T> findByNamedQuery(String query, Object value) throws PersistenceException;

    <T> List<T> findByNamedQuery(String query, Object[] values) throws PersistenceException;

    <T> List<T> findByProperty(Class clazz, String propertyName, Object value);

    <T> List<T> findByValueBean(String query, Object valueBean) throws PersistenceException;

    int updateOrDelete(String query) throws PersistenceException;

    public <T> T executeFind(HibernateCallback callback) throws PersistenceException;

    <T> List<T> findByNamedQueryAndNamedParam(String queryName, String paramName, Object value);

    <T> List<T>	findByNamedQueryAndNamedParam(String queryName, String[] paramNames, Object[] values);

    <T> T get(Class<T> clazz, Serializable id) ;
}

